package lz.controls
{

	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.TextEvent;
	
	import lz.controls.core.InvalidationType;
	import lz.controls.core.UIComponent;
	import lz.controls.events.ScrollEvent;
	/**
	 * UIScrollBar 类包括所有滚动条功能，只是添加了 scrollTarget 属性，因此能被附加到 TextField 实例或 TLFTextField 实例。
	 * 注意：当使用 ActionScript 更新影响文本布局的 TextField 或 TLFTextField 实例的属性时，必须对 UIScrollBar 组件实例调用 update() 方法以刷新其滚动属性。
	 * 属于 TextField 或 TLFTextField 实例的文本布局属性的示例有：width、height 和 wordWrap。
	 */
	public class UIScrollBar extends ScrollBar
	{
		/**
		 * @private (private)
		 */
		protected var _scrollTarget:DisplayObject;
		/**
		 * @private (private)
		 */
		protected var inEdit:Boolean=false;
		/**
		 * @private
		 */
		protected var inScroll:Boolean=false;
		/**
		 * @private
		 */
		protected var _targetScrollProperty:String;
		/**
		 * @private
		 */
		protected var _targetMaxScrollProperty:String;
		/**
		 * 默认样式
		 */
		private static var defaultStyles:Object={};
		/**
		 * 检索样式表
		 */
		public static function getStyleDefinition():Object
		{
			return UIComponent.mergeStyles(defaultStyles, ScrollBar.getStyleDefinition());
		}

		/**
		 * 创建新的 UIScrollBar 组件实例。
		 */
		public function UIScrollBar()
		{
			super();
		}

		/**
		 * @private
		 */
		override public function set minScrollPosition(minScrollPosition:Number):void
		{
			super.minScrollPosition=(minScrollPosition < 0) ? 0 : minScrollPosition;
		}
		/**
		 * @private
		 */
		override public function set maxScrollPosition(maxScrollPosition:Number):void
		{
			var maxScrollPos:Number=maxScrollPosition;
			if (_scrollTarget != null)
			{
				maxScrollPos=Math.min(maxScrollPos, _scrollTarget[_targetMaxScrollProperty]);
			}
			super.maxScrollPosition=maxScrollPos;
		}
		/**
		 * Registers a TextField instance or a TLFTextField instance with the ScrollBar component instance.
		 */
		public function get scrollTarget():DisplayObject
		{
			return _scrollTarget;
		}
		/**
		 * @private (setter)
		 */
		public function set scrollTarget(target:DisplayObject):void
		{
			if (_scrollTarget != null)
			{
				_scrollTarget.removeEventListener(Event.CHANGE, handleTargetChange, false);
				_scrollTarget.removeEventListener(TextEvent.TEXT_INPUT, handleTargetChange, false);
				_scrollTarget.removeEventListener(Event.SCROLL, handleTargetScroll, false);
			}
			_scrollTarget=target;

			// deal with switch to or away from bidi or vertical target
			var blockProg:String=null;
			var textDir:String=null;
			if (_scrollTarget != null)
			{
				try
				{
					if (_scrollTarget.hasOwnProperty("blockProgression"))
						blockProg=_scrollTarget["blockProgression"];
					if (_scrollTarget.hasOwnProperty("direction"))
						textDir=_scrollTarget["direction"];
				}
				catch (e:Error)
				{
					blockProg=null;
					textDir=null;
				}
			}
			var scrollHoriz:Boolean=(this.direction == ScrollBarDirection.HORIZONTAL);
			var rot:Number=Math.abs(this.rotation);
			if (scrollHoriz && (blockProg == "rl" || textDir == "rtl"))
			{
				// flip it around and shift it for right to left text
				if (getScaleY() > 0 && rotation == 90)
					x+=width;
				setScaleY(-1);
			}
			else if (!scrollHoriz && blockProg == "rl" && textDir == "rtl")
			{
				// flip it around it for right to left vertical text
				if (getScaleY() > 0 && rotation != 90)
					y+=height;
				setScaleY(-1);
			}
			else
			{
				if (getScaleY() < 0)
				{
					if (scrollHoriz)
					{
						if (rotation == 90)
							x-=width;
					}
					else
					{
						if (rotation != 90)
							y-=height;
					}
				}
				setScaleY(1);
			}
			// determine which APIs we call, horizontal or vertical
			setTargetScrollProperties(scrollHoriz, blockProg);

			// add event listeners if necessary
			if (_scrollTarget != null)
			{
				_scrollTarget.addEventListener(Event.CHANGE, handleTargetChange, false, 0, true);
				_scrollTarget.addEventListener(TextEvent.TEXT_INPUT, handleTargetChange, false, 0, true);
				_scrollTarget.addEventListener(Event.SCROLL, handleTargetScroll, false, 0, true);
			}
			invalidate(InvalidationType.DATA);
		}
		/**
		 * @private (internal)
		 * @internal For specifying in inspectable, and setting dropTarget
		 */
		public function get scrollTargetName():String
		{
			return _scrollTarget.name;
		}
		/**
		 * @private (setter)
		 */
		public function set scrollTargetName(target:String):void
		{
			try
			{
				scrollTarget=parent.getChildByName(target);
			}
			catch (error:Error)
			{
				throw new Error("ScrollTarget not found, or is not a valid target");
			}
		}
		/**
		 * @copy fl.controls.ScrollBar#direction
		 *
		 * @default ScrollBarDirection.VERTICAL
		 */
		override public function get direction():String
		{
			return super.direction;
		}
		/**
		 * @private (setter)
		 */
		override public function set direction(dir:String):void
		{
			// in live preview mode always render vertical
			if (isLivePreview)
				return;
			// if shifted and flipped for right to left and/or top to bottom, fix that first
			var cacheScrollTarget:DisplayObject;
			if (!componentInspectorSetting && _scrollTarget != null)
			{
				cacheScrollTarget=_scrollTarget;
				scrollTarget=null;
			}
			super.direction=dir;
			if (cacheScrollTarget != null)
			{
				scrollTarget=cacheScrollTarget;
			}
			else
			{
				updateScrollTargetProperties();
			}
		}
		/**
		 * 强制滚动条立即更新其 scroll 属性。 
		 * 使用 ActionScript 在指定的 scrollTarget 文本字段中添加文本后，必须执行此操作，并且需要刷新滚动条。
		 */
		public function update():void
		{
			inEdit=true;
			updateScrollTargetProperties();
			inEdit=false;
		}
		/**
		 * @private (protected)
		 */
		override protected function draw():void
		{
			if (isInvalid(InvalidationType.DATA))
			{
				updateScrollTargetProperties();
			}
			super.draw();
		}

		/**
		 * @private (protected)
		 */
		protected function updateScrollTargetProperties():void
		{
			if (_scrollTarget == null)
			{
				setScrollProperties(pageSize, minScrollPosition, maxScrollPosition);
				scrollPosition=0;
			}
			else
			{
				var blockProg:String=null;
				try
				{
					if (_scrollTarget.hasOwnProperty("blockProgression"))
						blockProg=_scrollTarget["blockProgression"];
				}
				catch (e1:Error)
				{
				}
				setTargetScrollProperties(this.direction == ScrollBarDirection.HORIZONTAL, blockProg);

				var pageSize:Number;
				var minScroll:Number;
				if (_targetScrollProperty == "scrollH")
				{
					minScroll=0;
					try
					{
						if (_scrollTarget.hasOwnProperty("controller") && _scrollTarget["controller"].hasOwnProperty("compositionWidth"))
						{
							pageSize=_scrollTarget["controller"]["compositionWidth"];
						}
						else
						{
							pageSize=_scrollTarget.width;
						}
					}
					catch (e2:Error)
					{
						pageSize=_scrollTarget.width;
					}
				}
				else
				{
					try
					{
						// hasOwnProperty will fail because it is in a namespace, so assume blockProg != null
						// means we are TLF and it will be there, and if not just catch error
						if (blockProg != null)
						{
							namespace local_tlf_internal="http://ns.adobe.com/textLayout/internal/2008";
							use namespace local_tlf_internal;
							var minScrollVValue:*=_scrollTarget["minScrollV"];
							if (minScrollVValue is int)
							{
								minScroll=minScrollVValue;
							}
							else
							{
								minScroll=1;
							}
						}
						else
						{
							minScroll=1;
						}
					}
					catch (e3:Error)
					{
						minScroll=1;
					}
					pageSize=10;
				}
				setScrollProperties(pageSize, minScroll, scrollTarget[_targetMaxScrollProperty]);
				scrollPosition=_scrollTarget[_targetScrollProperty];
			}
		}

		/**
		 * 设置 ScrollBar 组件的范围和视口大小。 
		 * ScrollBar 组件会相应地更新箭头按钮的状态和滚动滑块的大小。
		 * 所有滚动属性是相对于 minScrollPosition 和 maxScrollPosition 的缩放而言的。
		 * 介于最大值和最小值之间的每个数字都代表一个滚动位置。
		 * 参数
		 * pageSize:Number — 一个页面的大小。 确定滑块的大小以及单击箭头时滚动条移动的增量。
		 * minScrollPosition:Number — 滚动范围的底部。
		 * maxScrollPosition:Number — 滚动范围的顶部。
		 * pageScrollSize:Number (default = 0) — 单击轨道时移动的增量，以像素为单位。
		 */
		override public function setScrollProperties(pageSize:Number, minScrollPosition:Number, maxScrollPosition:Number, pageScrollSize:Number=0):void
		{
			var maxScrollPos:Number=maxScrollPosition;
			var minScrollPos:Number=(minScrollPosition < 0) ? 0 : minScrollPosition;

			if (_scrollTarget != null)
			{
				maxScrollPos=Math.min(maxScrollPosition, _scrollTarget[_targetMaxScrollProperty]);
			}
			super.setScrollProperties(pageSize, minScrollPos, maxScrollPos, pageScrollSize);
		}

		/**
		 * @private (protected)
		 */
		override public function setScrollPosition(scrollPosition:Number, fireEvent:Boolean=true):void
		{
			super.setScrollPosition(scrollPosition, fireEvent);
			if (!_scrollTarget)
			{
				inScroll=false;
				return;
			}
			updateTargetScroll();
		}

		// event default is null, so when user calls setScrollPosition, the text is updated, and we don't pass an event
		/**
		 * @private (protected)
		 */
		protected function updateTargetScroll(event:ScrollEvent=null):void
		{
			if (inEdit)
			{
				return;
			} // Update came from the user input. Ignore.
			_scrollTarget[_targetScrollProperty]=scrollPosition;
		}

		/**
		 * @private (protected)
		 */
		protected function handleTargetChange(event:Event):void
		{
			inEdit=true;
			setScrollPosition(_scrollTarget[_targetScrollProperty], true);
			updateScrollTargetProperties();
			inEdit=false;
		}

		/**
		 */
		protected function handleTargetScroll(event:Event):void
		{
			if (inDrag)
			{
				return;
			}
			if (!enabled)
			{
				return;
			}
			inEdit=true;
			updateScrollTargetProperties(); // This needs to be done first! 

			scrollPosition=_scrollTarget[_targetScrollProperty];
			inEdit=false;
		}

		/**
		 * 
		 */
		private function setTargetScrollProperties(scrollHoriz:Boolean, blockProg:String):void
		{
			if (blockProg == "rl")
			{
				if (scrollHoriz)
				{
					_targetScrollProperty="scrollV";
					_targetMaxScrollProperty="maxScrollV";
				}
				else
				{
					_targetScrollProperty="scrollH";
					_targetMaxScrollProperty="maxScrollH";
				}
			}
			else
			{
				if (scrollHoriz)
				{
					_targetScrollProperty="scrollH";
					_targetMaxScrollProperty="maxScrollH";
				}
				else
				{
					_targetScrollProperty="scrollV";
					_targetMaxScrollProperty="maxScrollV";
				}
			}
		}
	}
}
